package net.toby200.canalbuddy.notices;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

import com.google.android.gms.maps.MapFragment;

import net.toby200.canalbuddy.R;
import net.toby200.canalbuddy.notices.gcm.GcmRegistrar;
import net.toby200.canalbuddy.notices.map.CanalMapFragment;
import net.toby200.canalbuddy.notices.model.Notice;
import net.toby200.canalbuddy.notices.text.NoticeArrayAdapter;
import net.toby200.canalbuddy.notices.text.NoticeDetailFragment;
import net.toby200.canalbuddy.notices.text.NoticesListFragment;

import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.annotation.Nonnull;

import de.greenrobot.event.EventBus;


public class MainActivity extends Activity implements
         NoticesManager.TaskCallbacks {

    private static final Logger LOG = Logger.getLogger(MainActivity.class.getName());

    NoticesManager noticeManager;
    String gcmRegId;
    private ProgressDialog pd;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.notices_view);

        EventBus.getDefault().register(this);

        GcmRegistrar registrar = new GcmRegistrar(this);
        gcmRegId = registrar.getRegId();
        if (gcmRegId == null) {
            registrar.execute();
        }

        LOG.info("onCreate");
        FragmentManager fm = getFragmentManager();

        // create the notice manager. this is a fragment without a UI used to hold the list of
        // notices used by other fragments
        noticeManager = (NoticesManager) fm.findFragmentByTag(getString(R.string.notice_manager_frag));
        if (noticeManager == null) {
            noticeManager = new NoticesManager();
            fm.beginTransaction().add(noticeManager, getString(R.string.notice_manager_frag)).commit();
        }

        boolean specialIntent = handleIntent();

        if (!specialIntent && findViewById(R.id.notices_container) != null) {
            if (savedInstanceState == null) {
                // load the user's default screen
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
                int screenPref = prefs.getInt(getApplicationContext().getString(R.string.pref_last_screen), 0);
                setScreen(screenPref);
            }
        }

        noticeManager.loadNotices(getApplicationContext());
        new ActionBarHelper().setupSpinner(this);


    }

    /**
     * Handle any special intent that was passed in to the activity.
     *
     * If onCreate on onResume were called with an intent that contains a NOTICE extra then load
     * that notice detail and display it
     * @return true if a special intent was found, false if we should continue with standard opening process
     */
    private boolean handleIntent() {
        Intent intent = this.getIntent();
        boolean isSpecialIntent = false;
        boolean clearPendingNotifications = false;

        if (intent.hasExtra("net.toby200.canalbuddy.NOTICE")) {
            // main activity has been called from something e.g. notification with attached notice so
            // startup with this notice showing
            Notice notice = intent.getParcelableExtra("net.toby200.canalbuddy.NOTICE");
            LOG.info("Received notice in intent: " + notice);
            onNoticeSelectedEvent(notice);
            isSpecialIntent = true;
            clearPendingNotifications = true;
        } else if (intent.hasExtra("net.toby200.canalbuddy.NOTICE_LIST")) {
            LOG.info("Setting screen to show notice list");
            setScreen(0);
            isSpecialIntent = true;
            clearPendingNotifications = true;
        } else {
            LOG.info("No special intent to handle, loading preferred screen");
        }

        if (intent.hasExtra("net.toby200.canalbuddy.NOTICE_CLEAR")) {
            clearPendingNotifications = true;
        }

        if (clearPendingNotifications) {
            // Android doesn't honour the deleteIntent on a notification if the notification is dismissed
            // via autoCancel when clicked on rather than explicitly cancelled via swipe/delete all
            // so we cancel it manually here
            EventBus.getDefault().post(new Event.ClearNoticeNotificationsEvent());
        }

        return isSpecialIntent;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        FragmentTransaction ft = getFragmentManager().beginTransaction();

        if (id == R.id.action_settings) {
            ft.replace(R.id.notices_container, new SettingsFragment());
        }

        ft.addToBackStack("");
        ft.commit();
        return super.onOptionsItemSelected(item);
    }


    public void setScreen(int screenId) {
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();

        switch(screenId) {
            case 0:
                NoticesListFragment listFragment = (NoticesListFragment) fm.findFragmentByTag(getString(R.string.list_frag));
                if (listFragment == null) {
                    listFragment = new NoticesListFragment();
                }
                if (!listFragment.isVisible()) {
                    ft.replace(R.id.notices_container, listFragment, getString(R.string.list_frag));
                } else {
                    LOG.info("list_frag already visible, ignoring setScreen call as nothing to do");
                }

                break;
            case 1:
                MapFragment mapFragment = (MapFragment) fm.findFragmentByTag(getString(R.string.map_frag));
                if (mapFragment == null) {
                    mapFragment = CanalMapFragment.newInstance();
                }
                if (!mapFragment.isVisible()) {
                    ft.replace(R.id.notices_container, mapFragment, getString(R.string.map_frag));
                } else {
                    LOG.info("map_frag already visible, ignoring setScreen call as nothing to do");
                }

                break;
            default:
                LOG.warning("Unhandled screenId " + screenId);
        }
        ft.addToBackStack("").commit();

    }

    @Override
    protected void onResume() {
        LOG.info("onResume()");
        super.onResume();
        NoticeArrayAdapter adapter = getListAdapter();
        if (adapter != null) {
            LOG.info("registering list-adapter preference listener");
            PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
                    .registerOnSharedPreferenceChangeListener(adapter);
        }
        handleIntent();
    }

    @Override
    protected void onPause() {
        LOG.info("onPause()");
        super.onPause();
        NoticeArrayAdapter adapter = getListAdapter();
        if (adapter != null) {
            LOG.info("unregistering list-adapter preference listener");
            PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
                    .unregisterOnSharedPreferenceChangeListener(adapter);
        }
    }

    @Override
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
    }

    @Override
    public void onDestroy() {
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }


    @Override
    protected void onSaveInstanceState(@Nonnull Bundle outState) {
        super.onSaveInstanceState(outState);
    }

    public void onNoticeSelectedEvent(Notice notice) {
        LOG.info("onNoticeSelected(): " + notice.getTitle());
        FragmentTransaction ft = getFragmentManager().beginTransaction();

        NoticeDetailFragment detailFrag = new NoticeDetailFragment();
        Bundle noticeBundle = new Bundle();
        noticeBundle.putParcelable("notice", notice);
        detailFrag.setArguments(noticeBundle);

        ft.replace(R.id.notices_container, detailFrag).addToBackStack("").commit();
    }

    @Override
    public void onPreExecute() {
        LOG.log(Level.INFO, "Retrieving notices...");
        pd = new ProgressDialog(this);
        pd.setMessage("Retrieving Notices...");
        pd.show();
    }

    @Override
    public void onPostExecute(Collection<Notice> notices) {
        if (pd != null) {
            pd.dismiss();
        }

        LOG.info("Total " + notices.size() + " notices, updating UI");
        int noticeCount = notices.size();
        TextView text = (TextView) findViewById(R.id.notice_count_text);
        if (text != null) {
            text.setText("Loaded notices: " + noticeCount);
        }

        // update list adapter
        NoticeArrayAdapter adapter = getListAdapter();
        if (adapter != null) {
            adapter.onNoticeUpdate(notices);
        }

        CanalMapFragment mapFragment = (CanalMapFragment) getFragmentManager().findFragmentByTag(getString(R.string.map_frag));
        if (mapFragment != null) {
            mapFragment.onNoticeUpdate(notices);
        }


    }

    public NoticeArrayAdapter getListAdapter() {
        NoticesListFragment list = (NoticesListFragment) getFragmentManager().findFragmentByTag(getString(R.string.list_frag));
        return list != null ? (NoticeArrayAdapter) list.getListAdapter() : null;
    }

    public void setGCMRegId(String regId) {
        LOG.info("Received regId " + regId);
        gcmRegId = regId;
    }

    public void onEvent(Event.NoticeSelectedEvent noticeEvent) {
        LOG.info("Notice selected: " + noticeEvent.getNotice());
        onNoticeSelectedEvent(noticeEvent.getNotice());
    }

    public void onEvent(Object object) {
        LOG.info("onEvent: " + object);
    }
}
